#ifndef RENDER_RENDERER_H
#define RENDER_RENDERER_H

#include <graphics/material.h>
#include <graphics/mesh.h>
#include <graphics/rect.h>

namespace yam3d
{
namespace graphics
{
    class Image2D;
    class Image3D;
}

namespace render
{
    class Renderer : public core::Object
    {
    public:
        Renderer();
        virtual ~Renderer();

        void applyCamera( const math::mat4& matView, const math::mat4& matProj );
        void applyPass(const graphics::Pass* pass );
        void render(const graphics::Mesh* mesh, const math::mat4& meshTransform);
        void setViewport( int x, int y, int sizeX, int sizeY );
    private:
        void setRenderState(const graphics::RenderState* rs);
     //   void setSamplerState(const graphics::SamplerState* ss);
     //   void setVertexBuffer(graphics::VertexBuffer* vb);

        const graphics::Pass* m_pass;
        math::mat4 m_matView;
        math::mat4 m_matProj;
        graphics::Rect m_viewport;

        Renderer(const Renderer&);
        Renderer& operator=(const Renderer&);
    };

    class PerMaterialSortedRenderList : public core::Object
    {
    public:
        PerMaterialSortedRenderList();
        virtual ~PerMaterialSortedRenderList();

        void add( const graphics::Effect* effect, const graphics::Mesh* mesh, const math::mat4& transform );
        void clear()
        {
            m_renderLists.clear();
        }

        void render(Renderer* renderer, bool print = false) const;
    private:
       struct MeshTransform
       {
           MeshTransform(const graphics::Mesh* mesh, const math::mat4& transform)
               : m_mesh(mesh)
               , m_transform(transform)
           {
           }

           const graphics::Mesh* m_mesh;
           math::mat4 m_transform;
       };

        typedef core::vector<const MeshTransform*> MeshArray;
        typedef core::hash<const graphics::Effect*,MeshArray> HashType;
        HashType m_renderLists;

        PerMaterialSortedRenderList(const PerMaterialSortedRenderList&);
        PerMaterialSortedRenderList& operator=(const PerMaterialSortedRenderList&);
    };


    class UnsortedRenderList : public core::Object
    {
    public:
        UnsortedRenderList();
        virtual ~UnsortedRenderList();

        void add( const graphics::Effect* effect, const graphics::Mesh* mesh, const math::mat4& transform );
        void clear()
        {
            m_renderLists.clear();
        }

        void render(Renderer* renderer) const;
    private:
       struct MeshTransform
       {
           MeshTransform(const graphics::Effect* effect, const graphics::Mesh* mesh, const math::mat4& transform)
               : m_effect(effect)
               , m_mesh(mesh)
               , m_transform(transform)
           {
           }

           const graphics::Effect* m_effect;
           const graphics::Mesh* m_mesh;
           math::mat4 m_transform;
       };

        typedef core::vector<const MeshTransform*> MeshArray;
     //   typedef core::hash<const graphics::Effect*,MeshArray> HashType;
     //   HashType m_renderLists;
        MeshArray m_renderLists;

        UnsortedRenderList(const UnsortedRenderList&);
        UnsortedRenderList& operator=(const UnsortedRenderList&);
    };
}
}
#endif // RENDER_TEXTURE_H
